package com.hulk.ratel.test;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.HashMap;
import java.util.Map;



import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;

import com.hulk.ratel.common.security.RSAKey;
import fi.iki.elonen.NanoHTTPD;
import lombok.extern.slf4j.Slf4j;


//参考：https://www.cnblogs.com/exmyth/p/7524432.html

@Slf4j
public class App extends NanoHTTPD {

    public App() throws IOException {
        super(19085);
        start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
        System.out.println("\nRunning! Point your browsers to http://localhost:19085/ \n");
    }

    public static void main(String[] args) throws Exception {
        try {
            new App();
        } catch (IOException ioe) {
            System.err.println("Couldn't start server:\n" + ioe);
        }
    }

    @Override
    public Response serve(IHTTPSession session) {
        Map<String, String> files = new HashMap<String, String>();
        try {
            session.parseBody(files);
            //String param = files.get("postData");
            Method method = session.getMethod();
            String uri = session.getUri();
            log.info("method:{},uri:{}", method.toString(),uri);

            if ("/notify".equals(uri)&NanoHTTPD.Method.POST.equals(method)) {

                Map<String, String> header = session.getHeaders();

                Map<String, String> parms = session.getParms();

                log.info("header : " + header);
                log.info("parms : " + parms);

                String encryptData  = parms.get("encryptData");
                String signature =  parms.get("signature");
                String encryptKey =  parms.get("encryptKey");
                String partnerNo = parms.get("partnerNo");
                String traceId =   parms.get("traceId");

                PublicKey publicKey = RSAKey.getRSAPublicKeyByRelativeFileSuffix("key/rsa_public_key_2048.pem","pem");
                PrivateKey privateKey = RSAKey.getRSAPrivateKeyByRelativePathFileSuffix("key/partner_pkcs8_rsa_private_key_2048.pem","pem");

                //获取AES秘钥明文
                RSA rsa = new RSA();
                rsa.setPrivateKey(privateKey);
                String aesKey =  StrUtil.str(rsa.decrypt(Base64.decode(encryptKey, StandardCharsets.UTF_8), KeyType.PrivateKey),StandardCharsets.UTF_8);


                //解密合作方报文得到明文
                //SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, aesKey.getBytes(StandardCharsets.UTF_8));
                AES aes = new AES(Mode.ECB, Padding.PKCS5Padding,aesKey.getBytes(StandardCharsets.UTF_8));
                //解密
                String plainText = StrUtil.str(aes.decrypt(Base64.decode(encryptData, StandardCharsets.UTF_8)),StandardCharsets.UTF_8);


                //验证报文签名
               boolean flag =  checkSign(plainText,signature,publicKey);
               if(!flag){
                   log.error("签名验证失败");
                   return newFixedLengthResponse(Response.Status.OK, NanoHTTPD.MIME_PLAINTEXT, "FAILED");
               }

                //TODO
                // 处理业务逻辑

            } else {
                log.error("测试方法不支持");
                return newFixedLengthResponse(Response.Status.OK, NanoHTTPD.MIME_PLAINTEXT, "FAILED");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("未知异常",e);
            return newFixedLengthResponse(Response.Status.OK, NanoHTTPD.MIME_PLAINTEXT, "FAILED");
        }
        //return super.serve(session);
        return newFixedLengthResponse(Response.Status.OK, NanoHTTPD.MIME_PLAINTEXT, "000000");
    }


   private boolean checkSign(String plainText, String mac, PublicKey publicKey) {

        boolean isValid = false;
        try {
            byte [] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
            byte[] signPlainBytes = Base64.decode(mac);
            Signature signature = Signature.getInstance(SignAlgorithm.SHA256withRSA.getValue());
            signature.initVerify(publicKey);
            signature.update(plainBytes);
            isValid = signature.verify(signPlainBytes);
            return isValid;
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(String.format("验证数字签名时没有[%s]此类算法", SignAlgorithm.SHA256withRSA.getValue()),e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException("验证数字签名时公钥无效",e);
        } catch (SignatureException e) {
            throw new RuntimeException("验证数字签名时出现异常",e);
        }

    }

}
